/*
 * MIT License
 *
 * Copyright (c) 2023-present, tangli
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

package tony.test.core.enums

import jakarta.validation.ConstraintValidatorContext
import org.junit.jupiter.api.Assertions.assertFalse
import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Nested
import org.junit.jupiter.api.Test
import org.mockito.kotlin.mock
import org.mockito.kotlin.whenever
import tony.test.utils.AnnotationProxy
import tony.core.enums.DefaultAndAsNull
import tony.core.enums.IntEnumValue
import tony.core.enums.StringEnumValue
import tony.core.validate.IntEnum
import tony.core.validate.IntEnumValidator
import tony.core.validate.RangedIntEnum
import tony.core.validate.RangedIntEnumValidator
import tony.core.validate.RangedStringEnum
import tony.core.validate.RangedStringEnumValidator
import tony.core.validate.SimpleIntEnum
import tony.core.validate.SimpleIntEnumValidator
import tony.core.validate.SimpleStringEnum
import tony.core.validate.SimpleStringEnumValidator
import tony.core.validate.StringEnum
import tony.core.validate.StringEnumValidator

/**
 * 枚举验证器单元测试
 *
 * 测试所有枚举验证器的功能，包括有效值验证、无效值验证、必填验证、空值处理等场景
 *
 * @author tangli
 * @date 2025/01/23 14:00
 */
@DisplayName("枚举验证器单元测试")
class EnumValidatorsTest {

    private lateinit var context: ConstraintValidatorContext

    @BeforeEach
    fun setUp() {
        context = mock<ConstraintValidatorContext>()
    }

    // 测试用枚举类
    enum class TestIntEnum(override val value: Int) : IntEnumValue {
        ONE(1), TWO(2), THREE(3),
        @DefaultAndAsNull
        DEFAULT(-1)
    }

    enum class TestStringEnum(override val value: String) : StringEnumValue {
        HELLO("hello"), WORLD("world"),
        @DefaultAndAsNull
        DEFAULT("")
    }

    @Nested
    @DisplayName("RangedIntEnumValidator 测试")
    inner class RangedIntEnumValidatorTest {

        private lateinit var validator: RangedIntEnumValidator

        @BeforeEach
        fun setUp() {
            validator = RangedIntEnumValidator()
        }

        @Test
        @DisplayName("initialize(): 正确初始化验证器")
        fun testInitialize() {
            val annotation = mock<RangedIntEnum>()
            whenever(annotation.enums).thenReturn(intArrayOf(1, 2, 3))
            whenever(annotation.required).thenReturn(true)

            validator.initialize(annotation)
            // 验证初始化成功，通过后续测试验证
        }

        @Test
        @DisplayName("isValid(): 有效值验证通过")
        fun testValidValues() {
            val annotation = mock<RangedIntEnum>()
            whenever(annotation.enums).thenReturn(intArrayOf(1, 2, 3))
            whenever(annotation.required).thenReturn(false)
            validator.initialize(annotation)

            assertTrue(validator.isValid(TestIntEnum.ONE, context))
            assertTrue(validator.isValid(TestIntEnum.TWO, context))
            assertTrue(validator.isValid(TestIntEnum.THREE, context))
        }

        @Test
        @DisplayName("isValid(): 无效值验证失败")
        fun testInvalidValues() {
            val annotation = mock<RangedIntEnum>()
            whenever(annotation.enums).thenReturn(intArrayOf(1, 2))
            whenever(annotation.required).thenReturn(false)
            validator.initialize(annotation)

            assertFalse(validator.isValid(TestIntEnum.THREE, context))
        }

        @Test
        @DisplayName("isValid(): 必填验证 - 空值验证失败")
        fun testRequiredValidationWithNull() {
            val annotation = mock<RangedIntEnum>()
            whenever(annotation.enums).thenReturn(intArrayOf(1, 2, 3))
            whenever(annotation.required).thenReturn(true)
            validator.initialize(annotation)

            assertFalse(validator.isValid(null, context))
            assertFalse(validator.isValid(TestIntEnum.DEFAULT, context))
        }

        @Test
        @DisplayName("isValid(): 非必填验证 - 空值验证通过")
        fun testNonRequiredValidationWithNull() {
            val annotation = mock<RangedIntEnum>()
            whenever(annotation.enums).thenReturn(intArrayOf(1, 2, 3))
            whenever(annotation.required).thenReturn(false)
            validator.initialize(annotation)

            assertFalse(validator.isValid(null, context))
            assertFalse(validator.isValid(TestIntEnum.DEFAULT, context))
        }
    }

    @Nested
    @DisplayName("IntEnumValidator 测试")
    inner class IntEnumValidatorTest {

        private lateinit var validator: IntEnumValidator

        @BeforeEach
        fun setUp() {
            validator = IntEnumValidator()
        }

        @Test
        @DisplayName("initialize(): 正确初始化强类型枚举验证器")
        fun testInitializeWithValidEnum() {
            val annotation = AnnotationProxy.create(
                IntEnum::class.java,
                mapOf(
                    "enumClass" to TestIntEnum::class.java,
                    "required" to false,
                    "message" to "{tony.core.enums.validate.IntEnum.message}",
                    "groups" to emptyArray<Class<*>>(),
                    "payload" to emptyArray<Class<*>>()
                )
            )

            validator.initialize(annotation)
            // 验证初始化成功，通过后续测试验证
        }

        @Test
        @DisplayName("isValid(): 强类型枚举有效值验证通过")
        fun testValidEnumValues() {
            val annotation = AnnotationProxy.create(
                IntEnum::class.java,
                mapOf(
                    "enumClass" to TestIntEnum::class.java,
                    "required" to false,
                    "message" to "{tony.core.enums.validate.IntEnum.message}",
                    "groups" to emptyArray<Class<*>>(),
                    "payload" to emptyArray<Class<*>>()
                )
            )
            validator.initialize(annotation)

            assertTrue(validator.isValid(TestIntEnum.ONE, context))
            assertTrue(validator.isValid(TestIntEnum.TWO, context))
            assertTrue(validator.isValid(TestIntEnum.THREE, context))
        }

        @Test
        @DisplayName("isValid(): 必填验证 - 默认值验证失败")
        fun testRequiredValidationWithDefaultValue() {
            val annotation = AnnotationProxy.create(
                IntEnum::class.java,
                mapOf(
                    "enumClass" to TestIntEnum::class.java,
                    "required" to true,
                    "message" to "{tony.core.enums.validate.IntEnum.message}",
                    "groups" to emptyArray<Class<*>>(),
                    "payload" to emptyArray<Class<*>>()
                )
            )
            validator.initialize(annotation)

            assertFalse(validator.isValid(null, context))
            assertFalse(validator.isValid(TestIntEnum.DEFAULT, context))
            assertTrue(validator.isValid(TestIntEnum.ONE, context))
        }
    }

    @Nested
    @DisplayName("RangedStringEnumValidator 测试")
    inner class RangedStringEnumValidatorTest {

        private lateinit var validator: RangedStringEnumValidator

        @BeforeEach
        fun setUp() {
            validator = RangedStringEnumValidator()
        }

        @Test
        @DisplayName("initialize(): 正确初始化字符串范围验证器")
        fun testInitialize() {
            val annotation = mock<RangedStringEnum>()
            whenever(annotation.enums).thenReturn(arrayOf("hello", "world"))
            whenever(annotation.required).thenReturn(true)

            validator.initialize(annotation)
            // 验证初始化成功，通过后续测试验证
        }

        @Test
        @DisplayName("isValid(): 有效字符串值验证通过")
        fun testValidStringValues() {
            val annotation = mock<RangedStringEnum>()
            whenever(annotation.enums).thenReturn(arrayOf("hello", "world"))
            whenever(annotation.required).thenReturn(false)
            validator.initialize(annotation)

            assertTrue(validator.isValid(TestStringEnum.HELLO, context))
            assertTrue(validator.isValid(TestStringEnum.WORLD, context))
        }

        @Test
        @DisplayName("isValid(): 无效字符串值验证失败")
        fun testInvalidStringValues() {
            val annotation = mock<RangedStringEnum>()
            whenever(annotation.enums).thenReturn(arrayOf("hello"))
            whenever(annotation.required).thenReturn(false)
            validator.initialize(annotation)

            assertFalse(validator.isValid(TestStringEnum.WORLD, context))
        }

        @Test
        @DisplayName("isValid(): 必填验证 - 空值和默认值验证失败")
        fun testRequiredValidationWithNullAndDefault() {
            val annotation = mock<RangedStringEnum>()
            whenever(annotation.enums).thenReturn(arrayOf("hello", "world"))
            whenever(annotation.required).thenReturn(true)
            validator.initialize(annotation)

            assertFalse(validator.isValid(null, context))
            assertFalse(validator.isValid(TestStringEnum.DEFAULT, context))
        }
    }

    @Nested
    @DisplayName("StringEnumValidator 测试")
    inner class StringEnumValidatorTest {

        private lateinit var validator: StringEnumValidator

        @BeforeEach
        fun setUp() {
            validator = StringEnumValidator()
        }

        @Test
        @DisplayName("initialize(): 正确初始化强类型字符串枚举验证器")
        fun testInitializeWithValidStringEnum() {
            val annotation = AnnotationProxy.create(
                StringEnum::class.java,
                mapOf(
                    "enumClass" to TestStringEnum::class.java,
                    "required" to false,
                    "message" to "{tony.core.enums.validate.StringEnum.message}",
                    "groups" to emptyArray<Class<*>>(),
                    "payload" to emptyArray<Class<*>>()
                )
            )

            validator.initialize(annotation)
            // 验证初始化成功，通过后续测试验证
        }

        @Test
        @DisplayName("isValid(): 强类型字符串枚举有效值验证通过")
        fun testValidStringEnumValues() {
            val annotation = AnnotationProxy.create(
                StringEnum::class.java,
                mapOf(
                    "enumClass" to TestStringEnum::class.java,
                    "required" to false,
                    "message" to "{tony.core.enums.validate.StringEnum.message}",
                    "groups" to emptyArray<Class<*>>(),
                    "payload" to emptyArray<Class<*>>()
                )
            )
            validator.initialize(annotation)

            assertTrue(validator.isValid(TestStringEnum.HELLO, context))
            assertTrue(validator.isValid(TestStringEnum.WORLD, context))
        }

        @Test
        @DisplayName("isValid(): 必填验证 - 默认值验证失败")
        fun testRequiredValidationWithDefaultStringValue() {
            val annotation = AnnotationProxy.create(
                StringEnum::class.java,
                mapOf(
                    "enumClass" to TestStringEnum::class.java,
                    "required" to true,
                    "message" to "{tony.core.enums.validate.StringEnum.message}",
                    "groups" to emptyArray<Class<*>>(),
                    "payload" to emptyArray<Class<*>>()
                )
            )
            validator.initialize(annotation)

            assertFalse(validator.isValid(null, context))
            assertFalse(validator.isValid(TestStringEnum.DEFAULT, context))
            assertTrue(validator.isValid(TestStringEnum.HELLO, context))
        }
    }

    @Nested
    @DisplayName("SimpleStringEnumValidator 测试")
    inner class SimpleStringEnumValidatorTest {

        private lateinit var validator: SimpleStringEnumValidator

        @BeforeEach
        fun setUp() {
            validator = SimpleStringEnumValidator()
        }

        @Test
        @DisplayName("initialize(): 正确初始化简单字符串验证器")
        fun testInitialize() {
            val annotation = mock<SimpleStringEnum>()
            whenever(annotation.enums).thenReturn(arrayOf("option1", "option2"))

            validator.initialize(annotation)
            // 验证初始化成功，通过后续测试验证
        }

        @Test
        @DisplayName("isValid(): 有效字符串验证通过")
        fun testValidSimpleStringValues() {
            val annotation = mock<SimpleStringEnum>()
            whenever(annotation.enums).thenReturn(arrayOf("option1", "option2"))
            validator.initialize(annotation)

            assertTrue(validator.isValid("option1", context))
            assertTrue(validator.isValid("option2", context))
        }

        @Test
        @DisplayName("isValid(): 无效字符串验证失败")
        fun testInvalidSimpleStringValues() {
            val annotation = mock<SimpleStringEnum>()
            whenever(annotation.enums).thenReturn(arrayOf("option1", "option2"))
            validator.initialize(annotation)

            assertFalse(validator.isValid("option3", context))
            assertFalse(validator.isValid("invalid", context))
        }

        @Test
        @DisplayName("isValid(): 空值和空白字符串验证通过")
        fun testNullAndBlankStringValues() {
            val annotation = mock<SimpleStringEnum>()
            whenever(annotation.enums).thenReturn(arrayOf("option1", "option2"))
            validator.initialize(annotation)

            assertTrue(validator.isValid(null, context))
            assertTrue(validator.isValid("", context))
            assertTrue(validator.isValid("   ", context))
        }
    }

    @Nested
    @DisplayName("SimpleIntEnumValidator 测试")
    inner class SimpleIntEnumValidatorTest {

        private lateinit var validator: SimpleIntEnumValidator

        @BeforeEach
        fun setUp() {
            validator = SimpleIntEnumValidator()
        }

        @Test
        @DisplayName("initialize(): 正确初始化简单整数验证器")
        fun testInitialize() {
            val annotation = mock<SimpleIntEnum>()
            whenever(annotation.enums).thenReturn(intArrayOf(1, 2, 3))

            validator.initialize(annotation)
            // 验证初始化成功，通过后续测试验证
        }

        @Test
        @DisplayName("isValid(): 有效整数验证通过")
        fun testValidSimpleIntValues() {
            val annotation = mock<SimpleIntEnum>()
            whenever(annotation.enums).thenReturn(intArrayOf(1, 2, 3))
            validator.initialize(annotation)

            assertTrue(validator.isValid(1, context))
            assertTrue(validator.isValid(2, context))
            assertTrue(validator.isValid(3, context))
        }

        @Test
        @DisplayName("isValid(): 无效整数验证失败")
        fun testInvalidSimpleIntValues() {
            val annotation = mock<SimpleIntEnum>()
            whenever(annotation.enums).thenReturn(intArrayOf(1, 2, 3))
            validator.initialize(annotation)

            assertFalse(validator.isValid(4, context))
            assertFalse(validator.isValid(0, context))
            assertFalse(validator.isValid(-1, context))
        }

        @Test
        @DisplayName("isValid(): 空值验证通过")
        fun testNullIntValues() {
            val annotation = mock<SimpleIntEnum>()
            whenever(annotation.enums).thenReturn(intArrayOf(1, 2, 3))
            validator.initialize(annotation)

            assertTrue(validator.isValid(null, context))
        }
    }
}
